﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using UnityEngine.Networking;
namespace CommonLib {
	/// <summary>
	/// 资源加载器
	/// </summary>
	public class GameResourceLoader : ISingleton<GameResourceLoader>, IDisposable
	{
		/// <summary>
		/// 资源管理器
		/// </summary>
		GameResource GameResource { get; } = new GameResource();

		Hashtable LoadedCache;
		Dictionary<string, bool> LoadingCahce;
		private void Awake()
		{
			LoadedCache = new Hashtable();
			LoadingCahce = new Dictionary<string, bool>();
		}

		/// <summary>
		/// 直接使用地址来获取
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="path"></param>
		/// <returns></returns>
		virtual public T LoadFromResource<T>(string path) where T : UnityEngine.Object
		{
			return Resources.Load<T>(path);
		}

		public void LoadUIResSync<T>(string path, Action<T> onComplete = null, Action onFail = null, bool cache = false) where T : UnityEngine.Object
		{
			//获取资源位置 并 加载资源
			StartCoroutine(CorLoadFromResourceSync<T>(
				GameResource.UIResMgr.GetPath(AppPath.Resource, path),
				onComplete,
				onFail,
				cache
				));
		}


		//virtual protected void LoadFromResourceSync(string path, Action<UnityEngine.GameObject> onComplete = null, Action onFail = null)
		//{
		//	StartCoroutine(CorLoadFromResourceSync(path, onComplete, onFail));
		//}

		virtual protected IEnumerator CorLoadFromResourceSync<T>(string path, Action<T> onComplete = null, Action onFail = null, bool cache = false) where T : UnityEngine.Object
		{
			if (LoadingCahce.ContainsKey(path))
			{
				// have someone wait
				LoadingCahce[path] = true;
				while (LoadingCahce.ContainsKey(path))
				{
					//Current path is loading
					yield return new WaitForEndOfFrame();
				}
			}
			else
			{
				//start load
				LoadingCahce.Add(path, false);
			}

			if (LoadedCache.ContainsKey(path))
			{
				//had been loaded
				Debug.Log("load form cache");
				onComplete?.Invoke(LoadedCache[path] as T);
			}
			else
			{
				ResourceRequest request = Resources.LoadAsync<GameObject>(path);
				yield return request;
				if (null != request.asset)
				{
					//need add cache or have someone wait load
					if (cache || LoadingCahce[path])
						AddToCache(path, request.asset);
					onComplete?.Invoke(request.asset as T);
				}
				else
					onFail?.Invoke();
			}
			//end of loading
			LoadingCahce.Remove(path);
		}

		public string LoadJsonFileInPersistent(string path)
		{
#if !UNITY_EDITOR
			path = Path.Combine(Application.persistentDataPath, path);
#else
			path = Path.Combine(@"Assets\ResourcesFaker", path);
#endif
			string content;
			using(StreamReader sr = new StreamReader(new FileStream(path, FileMode.Open, FileAccess.Read)))
			{
				try
				{
					content = sr.ReadToEnd();
					return content;
				}
				catch(Exception e)
				{
					throw e;
				}
			}
		}


		[SerializeField]
		protected int m_CacheMaxCount = 20; 
		void AddToCache(string key, object value)
		{
			if (LoadedCache.Count > m_CacheMaxCount)
			{
				//移出策略
				Dispose();
			}
			if (!LoadedCache.ContainsKey(key))
				LoadedCache.Add(key, value);
		}

		virtual public void Dispose()
		{
			LoadedCache.Clear();
			Resources.UnloadUnusedAssets();
		}
	}
}